﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;

namespace Silverlight.Hosting.Private
{
    internal delegate void PaintBackgroundDelegate(PaintEventArgs e);
    
    internal class BufferedGraphicsRenderer : IDisposable
    {
        private BufferedGraphicsContext _context;
        private BufferedGraphics _graphics;
        private Control _control;
        private bool _disposed;
        private Size _lastSize;

        public BufferedGraphicsRenderer(Control control)
        {
            _control = control;
            _context = BufferedGraphicsManager.Current;
        }

        public BufferedGraphics BufferedGraphics
        {
            get { return _graphics; }
        }

        public void RenderFrame(FrameRenderedEventArgs args, PaintBackgroundDelegate paintBackground)
        {
            if (_disposed) throw new ObjectDisposedException("BufferedGraphicsRenderer");

            if (_graphics == null || args.Width != _lastSize.Width || args.Height != _lastSize.Height)
            {
                _context.MaximumBuffer = new Size(args.Width + 1, args.Height + 1);
                if (_graphics != null)
                {
                    _graphics.Graphics.Dispose();
                    _graphics.Dispose();
                    _graphics = null;
                }
                _graphics = _context.Allocate(_control.CreateGraphics(), new Rectangle(0, 0, args.Width, args.Height));

                _lastSize = new Size(args.Width, args.Height);
            }

            const int bpp = 32;
            int stride = (args.Width * bpp + 7) / 8;
            using (Bitmap image = new Bitmap(args.Width, args.Height, stride, PixelFormat.Format32bppArgb, args.Buffer))
            {
                paintBackground(new PaintEventArgs(_graphics.Graphics, new Rectangle(0, 0, args.Width, args.Height)));
                _graphics.Graphics.DrawImageUnscaled(image, new Point());
            }
        }

        ~BufferedGraphicsRenderer()
        {
            Dispose(false);
        }

        /// <summary>
        /// Release resources held by the target object
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (_graphics != null)
                {
                    _graphics.Graphics.Dispose();
                    _graphics.Dispose();
                    _graphics = null;
                }
                _control = null;
                _context = null;
            }
            _disposed = true;
        }
    }
}
